Libérez la puissance des compteurs CSS pour créer des systèmes de numérotation sophistiqués et dynamiques pour votre contenu web. Allez au-delà des listes simples avec des techniques avancées.
Fonctions de compteur CSS : Une exploration approfondie des systèmes de numérotation de listes avancés
En tant que développeurs web, nous rencontrons fréquemment le besoin de listes numérotées. L'élément HTML standard <ol> remplit bien cette fonction pour une numérotation séquentielle simple. Mais que se passe-t-il lorsque les exigences deviennent plus complexes ? Et si vous aviez besoin de numéroter des sections imbriquées comme 1.1.2, de créer des compteurs au style personnalisé, ou même de numéroter des éléments qui ne font pas du tout partie d'une liste, comme des titres ou des figures ? Pendant des années, ces tâches nécessitaient du JavaScript ou une logique côté serveur fastidieuse. Aujourd'hui, nous disposons d'une solution native puissante : les compteurs CSS.
Les compteurs CSS sont, en substance, des variables maintenues par CSS dont les valeurs peuvent être incrémentées par des règles que vous définissez. Ils offrent un moyen purement déclaratif de créer des systèmes de numérotation et d'étiquetage sophistiqués qui vont bien au-delà des capacités des listes ordonnées traditionnelles. Cette exploration approfondie vous guidera depuis les principes fondamentaux des compteurs CSS jusqu'aux techniques avancées et aux applications pratiques du monde réel qui peuvent améliorer la structure et la clarté de votre contenu web.
Comprendre les bases : Les trois piliers des compteurs CSS
L'ensemble du système de compteurs CSS repose sur trois propriétés fondamentales. Comprendre comment ces propriétés fonctionnent ensemble est la clé pour maîtriser cette fonctionnalité. Pensez-y comme un processus simple : vous initialisez un compteur, vous lui dites quand s'incrémenter, puis vous affichez sa valeur.
Pilier 1 : counter-reset - Initialiser votre compteur
La première étape de tout processus de comptage est d'établir un point de départ. La propriété counter-reset est utilisée pour créer et/ou réinitialiser un compteur. Vous l'appliquez généralement à un élément conteneur où vous souhaitez que le comptage commence.
Syntaxe :
counter-reset: <counter-name> [ <integer> ];
<counter-name>: C'est le nom que vous donnez à votre compteur (par ex.,section-counter,step,mon-super-compteur). Il est sensible à la casse.[ <integer> ]: Cette valeur optionnelle spécifie le nombre auquel le compteur doit être réinitialisé. Si elle est omise, la valeur par défaut est0. Vous pouvez utiliser des valeurs négatives.
Par exemple, pour démarrer un compteur nommé chapter pour un livre, vous pourriez l'appliquer au <body> ou à un conteneur principal <div> :
body {
counter-reset: chapter; /* Initialise le compteur 'chapter', la valeur est 0 */
}
.appendix {
counter-reset: appendix-counter -1; /* Initialise 'appendix-counter', commence Ă -1 */
}
Un concept important est la portée (scoping). Si vous utilisez counter-reset sur un élément imbriqué, cela crée une nouvelle instance indépendante de ce compteur dans la portée de cet élément.
Pilier 2 : counter-increment - Avancer le comptage
Une fois votre compteur initialisé, vous avez besoin d'un moyen de changer sa valeur. La propriété counter-increment augmente (ou diminue) la valeur d'un compteur, généralement juste avant qu'il ne soit utilisé.
Syntaxe :
counter-increment: <counter-name> [ <integer> ];
<counter-name>: Le nom du compteur à incrémenter.[ <integer> ]: Une valeur optionnelle spécifiant de combien incrémenter le compteur. La valeur par défaut est1. Vous pouvez utiliser0pour ne rien faire ou des valeurs négatives pour décrémenter.
Vous appliquez généralement ceci aux éléments que vous souhaitez compter. Par exemple, si vous numérotez des chapitres, vous incrémenteriez le compteur sur chaque balise <h1> représentant un titre de chapitre :
h1.chapter-title {
counter-increment: chapter; /* Incrémente 'chapter' de 1 */
}
Pilier 3 : counter() - Afficher la valeur
L'initialisation et l'incrémentation d'un compteur se font en coulisses. Pour rendre le compteur visible, vous devez afficher sa valeur. Cela se fait à l'aide de la fonction counter(), presque toujours dans la propriété content d'un pseudo-élément ::before ou ::after.
Syntaxe :
content: counter(<counter-name>);
En assemblant le tout, créons une liste numérotée personnalisée de base :
/* 1. Initialiser le compteur sur le conteneur */
.custom-list {
counter-reset: my-list-counter;
list-style-type: none; /* Masquer les marqueurs de liste par défaut */
padding-left: 0;
}
/* 2. Incrémenter le compteur sur chaque élément */
.custom-list li {
counter-increment: my-list-counter;
margin-bottom: 0.5em;
}
/* 3. Afficher la valeur du compteur */
.custom-list li::before {
content: counter(my-list-counter) ". ";
font-weight: bold;
color: #4a90e2;
margin-right: 0.5em;
}
Avec ce CSS, toute liste <ul class="custom-list"> s'affichera désormais comme une liste numérotée (1., 2., 3., etc.) sans utiliser de balise <ol>. Cet exemple simple démontre déjà la séparation du contenu (HTML) de la présentation (CSS), vous permettant de transformer une liste non ordonnée en une liste ordonnée avec seulement du CSS.
Au-delà des listes simples : Techniques de compteurs avancées
La véritable puissance des compteurs CSS se révèle lorsque vous dépassez les séquences simples. Explorons les fonctions et propriétés plus avancées qui permettent des systèmes de numérotation complexes.
Créer des compteurs imbriqués pour les plans et les annexes
L'un des cas d'utilisation les plus intéressants pour les compteurs est la création de numérotations hiérarchiques imbriquées, comme celles que l'on trouve dans les documents juridiques, les spécifications techniques ou les plans (par ex., 1., 1.1., 1.1.1., 1.2.). Ceci est réalisé avec la fonction counters().
La fonction counters() est similaire à counter(), mais elle est conçue pour l'imbrication. Elle récupère les valeurs de tous les compteurs du même nom qui se trouvent dans la portée actuelle et les joint avec une chaîne de séparation spécifiée.
Syntaxe :
content: counters(<counter-name>, '<separator-string>');
Voici comment créer une liste à plusieurs niveaux :
.outline {
counter-reset: section; /* Réinitialiser le compteur 'section' au niveau supérieur */
list-style-type: none;
padding-left: 1em;
}
.outline li {
counter-increment: section; /* Incrémenter pour chaque élément de la liste */
margin-bottom: 0.5em;
}
/* Réinitialiser le compteur pour toute liste imbriquée */
.outline ul {
counter-reset: section;
}
.outline li::before {
/* Afficher les valeurs des compteurs imbriqués, jointes par un point */
content: counters(section, ".") " ";
font-weight: bold;
margin-right: 0.5em;
}
Dans cet exemple, counter-reset: section; sur l'ul imbriqué est la clé. Il crée une nouvelle instance imbriquée du compteur `section` pour ce niveau. La fonction `counters()` remonte ensuite l'arborescence du DOM, collectant la valeur du compteur `section` à chaque niveau et les joignant avec un point. Le résultat est le schéma de numérotation classique 1., 1.1., 1.2., 2., 2.1.
Personnaliser les formats de compteur avec `list-style-type`
Et si vous aviez besoin de chiffres romains ou d'un ordre alphabétique ? Les fonctions counter() et counters() peuvent toutes deux accepter un deuxième argument optionnel qui spécifie le style de numérotation, en empruntant les valeurs disponibles pour la propriété `list-style-type`.
Syntaxe :
content: counter(<counter-name>, <list-style-type>);
Les valeurs courantes de `list-style-type` incluent :
decimal(1, 2, 3) - Par défautdecimal-leading-zero(01, 02, 03)lower-roman(i, ii, iii)upper-roman(I, II, III)lower-alpha/lower-latin(a, b, c)upper-alpha/upper-latin(A, B, C)lower-greek(α, β, γ)georgian,armenian, et bien d'autres pour les écritures internationales.
Stylisons un plan avec différents formats pour chaque niveau :
.detailed-outline > li::before {
content: counter(section, upper-roman) ". "; /* Niveau 1 : I, II, III */
}
.detailed-outline > li > ul > li::before {
content: counter(section, upper-alpha) ". "; /* Niveau 2 : A, B, C */
}
.detailed-outline > li > ul > li > ul > li::before {
content: counter(section, decimal) ". "; /* Niveau 3 : 1, 2, 3 */
}
Combiner les compteurs avec des chaînes de caractères et des attributs
La propriété content n'est pas limitée à la seule fonction de compteur. Vous pouvez concaténer des chaînes de caractères, d'autres fonctions CSS comme attr(), et plusieurs compteurs pour créer des étiquettes très descriptives.
h2::before {
content: "Section " counter(section) ": ";
}
.footnote::before {
counter-increment: footnote;
content: "[" counter(footnote) "]";
font-size: 0.8em;
vertical-align: super;
margin-right: 0.2em;
}
/* Utilisation de attr() pour extraire d'un attribut de données */
blockquote::before {
counter-increment: quote;
content: "Citation n°" counter(quote) " (Source : " attr(cite) ") ";
display: block;
font-style: italic;
color: #666;
}
Contrôler l'incrémentation : pas et décrémentation
La propriété counter-increment peut prendre un second argument pour contrôler la valeur du pas. Cela vous permet de compter de deux en deux, de cinq en cinq, ou même de compter à rebours en fournissant un nombre négatif.
Compter de deux en deux (nombres pairs) :
.even-list {
counter-reset: even-counter 0;
}
.even-list li {
counter-increment: even-counter 2;
}
.even-list li::before {
content: counter(even-counter);
}
Créer un compte à rebours :
.countdown {
counter-reset: launch 11; /* Commencer par réinitialiser à 11 */
}
.countdown li {
counter-increment: launch -1; /* Décrémenter de 1 à chaque fois */
}
.countdown li::before {
content: counter(launch);
}
Cette technique simple est étonnamment puissante pour des listes spécialisées ou des éléments d'interface utilisateur qui nécessitent un séquençage non standard.
Cas d'utilisation pratiques : lĂ oĂą les compteurs CSS excellent
La théorie, c'est bien, mais voyons comment ces techniques résolvent des problèmes du monde réel. Les compteurs CSS ne sont pas seulement pour les listes ; ils peuvent structurer un document entier.
Cas d'utilisation 1 : Numéroter les titres automatiquement
L'une des applications les plus classiques et utiles est la numérotation automatique des titres de documents. Cela garantit que les numéros de vos sections sont toujours corrects, même si vous réorganisez, ajoutez ou supprimez des sections. Aucune mise à jour manuelle requise !
body {
counter-reset: h1-counter;
}
h1 {
counter-reset: h2-counter; /* Réinitialiser le compteur h2 chaque fois qu'un h1 apparaît */
}
h2 {
counter-reset: h3-counter; /* Réinitialiser le compteur h3 chaque fois qu'un h2 apparaît */
}
h1::before {
counter-increment: h1-counter;
content: counter(h1-counter) ". ";
}
h2::before {
counter-increment: h2-counter;
content: counter(h1-counter) "." counter(h2-counter) ". ";
}
h3::before {
counter-increment: h3-counter;
content: counter(h1-counter) "." counter(h2-counter) "." counter(h3-counter) ". ";
}
Cette solution élégante crée une structure de document robuste et auto-entretenue. La magie réside dans la réinitialisation du compteur enfant sur le titre parent, ce qui définit correctement la portée de la numérotation à chaque niveau.
Cas d'utilisation 2 : Légendes d'images et de figures
Numéroter automatiquement les figures, les tableaux et les images dans un long article ajoute une touche professionnelle et facilite leur référencement dans le texte.
body {
counter-reset: figure-counter table-counter;
}
figure figcaption::before {
counter-increment: figure-counter;
content: "Figure " counter(figure-counter) ": ";
font-weight: bold;
}
table caption::before {
counter-increment: table-counter;
content: "Tableau " counter(table-counter) ": ";
font-weight: bold;
}
Maintenant, chaque <figcaption> et <caption> sur la page sera automatiquement préfixé avec le numéro séquentiel correct.
Cas d'utilisation 3 : Guides et tutoriels pas à pas avancés
Pour les tutoriels, les recettes ou les guides, une numérotation claire des étapes est essentielle. Les compteurs CSS vous permettent de créer des étapes visuellement riches et en plusieurs parties.
.tutorial {
counter-reset: main-step;
font-family: sans-serif;
}
.step {
counter-increment: main-step;
counter-reset: sub-step;
border: 1px solid #ccc;
padding: 1em;
margin: 1em 0;
position: relative;
}
.step > h3::before {
content: "Étape " counter(main-step, decimal-leading-zero);
background-color: #333;
color: white;
padding: 0.2em 0.5em;
border-radius: 4px;
margin-right: 1em;
}
.sub-step {
counter-increment: sub-step;
margin-left: 2em;
margin-top: 0.5em;
}
.sub-step::before {
content: counter(main-step, decimal) "." counter(sub-step, lower-alpha);
font-weight: bold;
margin-right: 0.5em;
}
Cela crée une hiérarchie visuelle claire, où les étapes principales reçoivent un numéro stylisé proéminent (par ex., "Étape 01") et les sous-étapes des étiquettes imbriquées (par ex., "1.a", "1.b").
Cas d'utilisation 4 : Compter les éléments sélectionnés
C'est un cas d'utilisation plus dynamique et interactif. Vous pouvez utiliser des compteurs pour garder un total courant des éléments sélectionnés par l'utilisateur, comme des cases à cocher, sans aucun JavaScript.
.checklist-container {
counter-reset: checked-items 0;
}
/* N'incrémenter le compteur que si la case est cochée */
.checklist-container input[type="checkbox"]:checked {
counter-increment: checked-items;
}
/* Afficher le total dans un élément séparé */
.total-count::after {
content: counter(checked-items);
font-weight: bold;
}
/* Le HTML ressemblerait Ă : */
/*
Total des éléments sélectionnés :
*/
Lorsque l'utilisateur coche et décoche les cases, le nombre affiché dans .total-count::after se mettra à jour automatiquement. Cela démontre comment les compteurs peuvent réagir aux états des éléments, ouvrant des possibilités pour des retours d'interface utilisateur simples, uniquement en CSS.
Considérations sur l'accessibilité et le SEO
Bien que les compteurs CSS soient incroyablement puissants pour la présentation visuelle, il est crucial de considérer leur impact sur l'accessibilité et le SEO. Le contenu généré par la propriété content se situe dans une zone grise.
Historiquement, les lecteurs d'écran ne lisaient pas le contenu des pseudo-éléments ::before et ::after. Bien que les lecteurs d'écran modernes se soient améliorés, le support peut encore être incohérent. Une liste numérotée visuellement pourrait être annoncée comme une simple liste non numérotée à un utilisateur de technologie d'assistance, lui faisant perdre un contexte structurel important.
La solution ARIA
Lorsque vous utilisez des compteurs CSS pour remplacer la fonctionnalité d'un <ol> standard, vous supprimez la sémantique que l'élément HTML fournit. Vous devriez rajouter cette signification sémantique en utilisant les rôles ARIA (Accessible Rich Internet Applications).
Pour une liste numérotée personnalisée construite avec des <div>, vous pourriez faire :
<div role="list">
<div role="listitem">Premier élément</div>
<div role="listitem">Deuxième élément</div>
</div>
Cependant, la meilleure pratique est souvent d'utiliser le HTML le plus sémantique possible. Si votre contenu est une liste, utilisez <ol>. Vous pouvez toujours utiliser les compteurs CSS pour styliser ses marqueurs en masquant le marqueur par défaut (list-style: none) et en appliquant votre compteur personnalisé avec ::before. De cette façon, vous obtenez le meilleur des deux mondes : un style robuste et une sémantique intégrée.
Pour les éléments qui ne sont pas des listes, comme les titres numérotés, l'histoire de l'accessibilité est meilleure. Le numéro généré est purement présentationnel ; la structure sémantique est transmise par les balises <h1>, <h2> elles-mêmes, que les lecteurs d'écran annoncent correctement.
Implications pour le SEO
Similairement à l'accessibilité, les robots des moteurs de recherche peuvent ou non analyser et indexer le contenu généré par CSS. Le consensus général est que vous ne devriez jamais placer de contenu critique et unique à l'intérieur d'une propriété `content`. Les nombres générés par les compteurs ne sont généralement pas du contenu unique et critique — ce sont des métadonnées structurelles. En tant que tel, les utiliser pour numéroter des titres ou des figures est généralement considéré comme sûr pour le SEO, car le contenu principal se trouve dans le HTML lui-même.
Support des navigateurs
L'une des meilleures choses à propos des compteurs CSS est leur excellent support par les navigateurs. Ils sont pris en charge par tous les principaux navigateurs depuis plus d'une décennie. Selon caniuse.com, `counter-increment` et `counter-reset` sont supportés par plus de 99% des navigateurs dans le monde. Cela inclut toutes les versions modernes de Chrome, Firefox, Safari et Edge, et remonte même à Internet Explorer 8.
Cela signifie que vous pouvez utiliser les compteurs CSS en toute confiance aujourd'hui sans avoir besoin de solutions de repli complexes ou de vous soucier des problèmes de compatibilité pour la grande majorité de vos utilisateurs dans le monde.
Conclusion
Les compteurs CSS transforment la numérotation d'une fonctionnalité rigide et liée au HTML en un outil de conception flexible et dynamique. En maîtrisant le trio de base de counter-reset, counter-increment, et des fonctions counter()/counters(), vous pouvez aller au-delà des listes simples et construire des systèmes de numérotation sophistiqués et auto-entretenus pour n'importe quel élément de votre page.
De la numérotation automatique des chapitres et des figures dans la documentation technique à la création de listes de contrôle interactives et de tutoriels magnifiquement stylisés, les compteurs CSS offrent une solution puissante, performante et purement basée sur CSS. Bien qu'il soit important de garder l'accessibilité à l'esprit et d'utiliser le HTML sémantique comme base, les compteurs CSS sont un outil essentiel dans la boîte à outils du développeur front-end moderne pour créer un code plus propre et un contenu plus intelligent et structuré.